using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.IO;

namespace WindowsApplication4
{
    /// <summary>
    /// Handles management of all compaigns in a data table, adding, saving, and selecting
    /// </summary>
    public class CompaignManager
    {
        public class CONSTS
        {
            public class CompaignColumns
            {
                public static int CompaignIDIndex = 0;
                public static int NameIndex = 1;
                public static int DescriptionIndex = 2;
            }

            public class TargetColumns
            {
                public static int TargetIDIndex = 0;
                public static int CompaignIDIndex = 1;
                public static int VillageIDIndex = 2;
                public static int DescriptionIndex = 3;
                public static int LaunchedIndex = 4;
            }

            public class AttackColumns
            {
                public static int AttackIDIndex = 0;
                public static int TargetIDIndex = 1;
                public static string TargetIDName = "TargetID";
                public static int AttackingVillageIDIndex = 2;
                public static int UnitIndex = 3;
                public static int DescriptionIndex = 4;
                public static int PriorityIndex = 5;
                public static string PriorityName = "Priority";
                public static int TimeLaunchedIndex = 6;
                public static string TimeLaunchedName = "TimeLaunched";
                public static int AttackLaunchedIndex = 7;
            }

            public class Relations
            {
                public static string CompaignToTarget = "CompaignToTarget";
                public static string TargetToAttack = "TargetToAttack";
            }

            public static string CompaignsFile = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @".\TW++ Saved Files\w3compaigns.xml";
        }

        #region Public variables
        public  DataSet dsCompaign;
        public  DataTable dtCompaigns;
        public  DataTable dtTargets;
        public  DataTable dtAttacks;
        #endregion

        /// <summary>
        /// Default constructor
        /// </summary>
        public CompaignManager()
        {
            //Data column used to add id columns to data tables
            DataColumn col;

            //Create a new data set
            this.dsCompaign = new DataSet();

            #region Compaigns data table
            //Create a new data table for the compaigns
            this.dtCompaigns = new DataTable("Compaigns");
            //Add a new column for compaign id to data table
            col = this.dtCompaigns.Columns.Add("CompaignID", System.Type.GetType("System.Int32"));
            //Set compaign id column settings
            col.AllowDBNull = false;
            col.AutoIncrement = true;
            col.AutoIncrementSeed = -10;
            col.AutoIncrementStep = -1;
            //Add name column
            this.dtCompaigns.Columns.Add("Name", System.Type.GetType("System.String"));
            //Add description column
            this.dtCompaigns.Columns.Add("Description", System.Type.GetType("System.String"));
            #endregion

            #region Targets data table
            //Add a new data table for targets
            this.dtTargets = new DataTable("Targets");
            //Add a target id column and set settings
            col = this.dtTargets.Columns.Add("TargetID", System.Type.GetType("System.Int32"));
            col.AllowDBNull = false;
            col.AutoIncrement = true;
            col.AutoIncrementSeed = -10;
            col.AutoIncrementStep = -1;
            //Add compaign id column
            this.dtTargets.Columns.Add("CompaignID", System.Type.GetType("System.Int32"));
            //Add village id column
            this.dtTargets.Columns.Add("VillageID", System.Type.GetType("System.Int32"));
            //Add description column
            this.dtTargets.Columns.Add("Description", System.Type.GetType("System.String"));
            //Add launched column and set default to false
            col = this.dtTargets.Columns.Add("Launched", System.Type.GetType("System.Boolean"));
            col.DefaultValue = false;
            #endregion

            #region Attacks data table
            //Create attacks data table
            this.dtAttacks = new DataTable("Attacks");
            //Add a column for attack id and set settings
            col = this.dtAttacks.Columns.Add("AttackID", System.Type.GetType("System.Int32"));
            col.AllowDBNull = false;
            col.AutoIncrement = true;
            col.AutoIncrementSeed = -10;
            col.AutoIncrementStep = -1;
            //Add target id column
            this.dtAttacks.Columns.Add("TargetID", System.Type.GetType("System.Int32"));
            //Add attacking village id column
            this.dtAttacks.Columns.Add("AttackingVillageID", System.Type.GetType("System.Int32"));
            //Add unit column
            this.dtAttacks.Columns.Add("Unit", System.Type.GetType("System.String"));
            //Add description column
            this.dtAttacks.Columns.Add("Description", System.Type.GetType("System.String"));
            //Add priority column
            this.dtAttacks.Columns.Add("Priority", System.Type.GetType("System.Int32"));
            //Add time launched column and set default value to smallest time possible
            col = this.dtAttacks.Columns.Add("TimeLaunched", System.Type.GetType("System.DateTime"));
            col.DefaultValue = DateTime.MinValue;
            //Add attack launched column and set default to false
            col = this.dtAttacks.Columns.Add("AttackLaunched", System.Type.GetType("System.Boolean"));
            col.DefaultValue = false;
            #endregion

            //Add data tables to data set
            this.dsCompaign.Tables.Add(dtCompaigns);
            this.dsCompaign.Tables.Add(dtTargets);
            this.dsCompaign.Tables.Add(dtAttacks);

            //Set the primary key of each data table to the id column
            this.dtCompaigns.PrimaryKey = new DataColumn[] { this.dtCompaigns.Columns[CONSTS.CompaignColumns.CompaignIDIndex] };
            this.dtTargets.PrimaryKey = new DataColumn[] { this.dtTargets.Columns[CONSTS.TargetColumns.TargetIDIndex] };
            this.dtAttacks.PrimaryKey = new DataColumn[] { this.dtAttacks.Columns[CONSTS.AttackColumns.AttackIDIndex] };

            //Add a relationship between the compaign id in the compaign data table and the target data table
            this.dsCompaign.Relations.Add("CompaignToTarget", this.dtCompaigns.Columns[CONSTS.CompaignColumns.CompaignIDIndex]
                , this.dtTargets.Columns[CONSTS.TargetColumns.CompaignIDIndex]);
            //Add a relationship between the target id in the target data table and the attack data table
            this.dsCompaign.Relations.Add("TargetToAttack", this.dtTargets.Columns[CONSTS.TargetColumns.TargetIDIndex]
                , this.dtAttacks.Columns[CONSTS.AttackColumns.TargetIDIndex]);

            //If the compaign file exists
            if (File.Exists(CONSTS.CompaignsFile))
            {
                try
                {
                    //Read the xml from the compaign file into the data set
                    this.dsCompaign.ReadXml(CONSTS.CompaignsFile, XmlReadMode.IgnoreSchema);
                }
                catch (Exception e)
                {
                    error frmError = new error();
                    frmError.textBox1.Text = e.Message + "\n" + e.StackTrace;
                    frmError.ShowDialog();
                }                
            }
            /*
            //
            // TEST CODE
            //
            DataRow dr = dtCompaigns.Rows.Add(new object[] { null, "Test1", "Test desc" });

            dr = dtTargets.Rows.Add(new object[] { null, dr[0], 64454,"bad bad target" });
            dtAttacks.Rows.Add(new object[] {null, dr[0], 64713, "Ram", "Real attack",0 });

            dr = dtCompaigns.Rows.Add(new object[] { null, "Test2", "Test 2 desc" });

            dr = dtTargets.Rows.Add(new object[] { null, dr[0], 64454, "much better target" });
            dtAttacks.Rows.Add(new object[] { null, dr[0], 64713, "Axe", "almost Real attack", 0 });

            dr = dtTargets.Rows.Add(new object[] { null, dr[0], 64455, "much better target2" });
            dtAttacks.Rows.Add(new object[] { null, dr[0], 64714, "Ram", "clear", 0 });
            dtAttacks.Rows.Add(new object[] { null, dr[0], 64714, "Axe", "clear2", 0 });
            dtAttacks.Rows.Add(new object[] { null, dr[0], 64715, "Nobleman", "almost Real attack3", 1 });
            dtAttacks.Rows.Add(new object[] { null, dr[0], 64716, "Nobleman", "almost Real attack3", 1 });
            dtAttacks.Rows.Add(new object[] { null, dr[0], 64715, "Nobleman", "almost Real attack3", 2 });
            */

            //Commits changes made to data set
            this.dsCompaign.AcceptChanges();
        }

        #region Indexers
        /// <summary>
        /// Gets compaign at given index
        /// </summary>
        /// <param name="name">Compaign to get</param>
        /// <returns></returns>
        public Compaign this[String name]
        {
            get
            {
                //Select data rows that have the given compaign name
                DataRow[] rows = this.dtCompaigns.Select("Name = '" + name + "'");

                //If there is at least one row with the input compaign name
                if (rows.Length > 0)
                {
                    //Return the first compaign found
                    return new Compaign(rows[0], this);
                }
                else
                {
                    return null;
                }
            }
        }

        /// <summary>
        /// Gets the compaign at the given index
        /// </summary>
        /// <param name="id">Id of compaign to get</param>
        /// <returns></returns>
        public Compaign this[int id]
        {
            get
            {
                //Get the data row at the with the input compaign id
                DataRow row = this.dtCompaigns.Rows.Find(id);

                //If there is a row with the input id
                if (row != null)
                {
                    //Return the compaign
                    return new Compaign(row, this);
                }
                else
                {
                    return null;
                }
            }
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets a list of all compaigns
        /// </summary>
        public List<Compaign> AllCompaigns
        {
            get
            {
                //If there are no compaigns
                if (this.dtCompaigns.Rows.Count == 0)
                {
                    //Return an empty list
                    return new List<Compaign>(0);
                }
                else
                {
                    //Create a new list
                    List<Compaign> compaigns = new List<Compaign>(this.dtCompaigns.Rows.Count);

                    //Gets all data rows of compaigns
                    DataRow[] drs = this.dtCompaigns.Select(); // use select to make sure we do not get deleted rows.
                    //For each compaign data row
                    foreach (DataRow dr in drs)
                    {
                        //Add compaign to list
                        compaigns.Add(new Compaign(dr, this));
                    }

                    //Return list of all compaigns
                    return compaigns;
                }
            }
        }

        /// <summary>
        /// Gets if there are changes in the data set
        /// </summary>
        public bool AreThereChanges
        {
            get
            {
                return this.dsCompaign.HasChanges();
            }
        }
        #endregion

        #region Methods
        /// <summary>
        /// Adds a new compaign with the given name
        /// </summary>
        /// <param name="name">Name of new compaign</param>
        /// <returns>New compaign created</returns>
        public Compaign Add(string name)
        {
            //Add a new data row to the compaigns data table for the new compaign
            DataRow dr = this.dtCompaigns.Rows.Add(new object[] { null, name, "" });
            //Return a new compaign
            return new Compaign(dr, this);

        }

        /// <summary>
        /// Saves data set to compaign xml file
        /// </summary>
        public void Save() 
        {
            //Save data set to xml file
            this.dsCompaign.WriteXml(CONSTS.CompaignsFile);
            //Accept all changes in data set
            this.dsCompaign.AcceptChanges();
        }
        #endregion
    }
}
